package ink.tsg.createert.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import ink.tsg.createert.entity.ErtExcleDto;
import ink.tsg.createert.entity.ErtTargetExcleDto;
import ink.tsg.createert.entity.ReqDot;
import org.apache.commons.math3.analysis.interpolation.LinearInterpolator;
import org.apache.tomcat.util.bcel.classfile.Constant;
import org.springframework.stereotype.Controller;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.zeroturnaround.zip.ZipEntryCallback;
import org.zeroturnaround.zip.ZipUtil;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.zip.ZipEntry;

/**
 * @author geo_tsg
 * @version 1.0.0
 * @ClassName ERTBuildController.java
 * @Description
 * @createTime 2021-09-23
 */
//@RestController
@RequestMapping
@Controller
@CrossOrigin
public class ErtBuildController {

    //MultipartFile calcu, MultipartFile target, HttpServletResponse response
    @PostMapping("ertBuild")
    public void ertBuild(@Validated ReqDot reqDot,
                         HttpServletResponse response) {
        if (reqDot.getStep() <= 0) {
            throw new RuntimeException("步长不能小于零");
        } else {
            System.out.println("开始计算");
            ExcelWriter excelWriter = null;
            try {
                List<ErtExcleDto> ertExcleDtos = EasyExcel.read(reqDot.getCalcu().getInputStream()).head(ErtExcleDto.class).sheet().doReadSync();
                int newSize = (int) Math.ceil((ertExcleDtos.get(ertExcleDtos.size() - 1).getPoint() - ertExcleDtos.get(0).getPoint()) / 0.5);
                List<ErtExcleDto> newErtExcleDtos = new ArrayList<>(newSize);
                for (int i = 0; i < ertExcleDtos.size() - 1; i++) {
                    int j = i;
                    ErtExcleDto ertExcleDtoA = ertExcleDtos.get(j);
                    ErtExcleDto ertExcleDtoB = ertExcleDtos.get(++j);
                    newErtExcleDtos.add(ertExcleDtoA);
                    double[] point = new double[]{ertExcleDtoA.getPoint(), ertExcleDtoB.getPoint()};
                    double[] north = new double[]{ertExcleDtoA.getNorth(), ertExcleDtoB.getNorth()};
                    double[] east = new double[]{ertExcleDtoA.getEast(), ertExcleDtoB.getEast()};
                    double[] elv = new double[]{ertExcleDtoA.getElv(), ertExcleDtoB.getElv()};
                    for (double k = ertExcleDtoA.getPoint() + reqDot.getStep(); k < ertExcleDtoB.getPoint(); k += reqDot.getStep()) {
                        ErtExcleDto ertExcleDto = new ErtExcleDto();
                        // 创建线性插值的对象
                        LinearInterpolator line = new LinearInterpolator();
                        ertExcleDto.setNorth(Double.valueOf(NumberUtil.roundStr(line.interpolate(point, north).value(k), 3)));
                        ertExcleDto.setEast(Double.valueOf(NumberUtil.roundStr(line.interpolate(point, east).value(k), 3)));
                        ertExcleDto.setElv(Double.valueOf(NumberUtil.roundStr(line.interpolate(point, elv).value(k), 3)));
                        ertExcleDto.setPoint(k);
                        newErtExcleDtos.add(ertExcleDto);
                    }
                }
                newErtExcleDtos.add(ertExcleDtos.get(ertExcleDtos.size() - 1));
                List<ErtTargetExcleDto> targets = EasyExcel.read(reqDot.getTarget().getInputStream()).head(ErtTargetExcleDto.class).sheet().doReadSync();
                for (ErtExcleDto newErtExcleDto : newErtExcleDtos) {
                    for (ErtTargetExcleDto ertTargetExcleDto : targets) {
                        if (Math.abs(newErtExcleDto.getPoint() - ertTargetExcleDto.getPoint()) < 0.00000000001) {
                            ertTargetExcleDto.setX(Double.valueOf(NumberUtil.roundStr(newErtExcleDto.getEast(), 3)));
                            ertTargetExcleDto.setY(Double.valueOf(NumberUtil.roundStr(newErtExcleDto.getNorth(), 3)));
                            ertTargetExcleDto.setElv(Double.valueOf(NumberUtil.roundStr(newErtExcleDto.getElv(), 3)));
                            ertTargetExcleDto.setEleDepth(Double.valueOf(NumberUtil.roundStr(newErtExcleDto.getElv() + ertTargetExcleDto.getElevation(), 3)));
                        }
                    }
                }
                String filename = reqDot.getCalcu().getOriginalFilename().substring(0, reqDot.getCalcu().getOriginalFilename().lastIndexOf("."));
                if ("dat".equalsIgnoreCase(reqDot.getFileType())) {
                    createDat(newErtExcleDtos, targets, filename, response);
                    return;
                }
                // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
                response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                response.setCharacterEncoding("utf-8");
                // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
                String fileName = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
                response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
                excelWriter = EasyExcel.write(response.getOutputStream()).build();
                WriteSheet allSheet = EasyExcel.writerSheet("all").head(ErtExcleDto.class).build();
                WriteSheet writeSheet = EasyExcel.writerSheet("ert111_topres").head(ErtTargetExcleDto.class).build();
                excelWriter.write(newErtExcleDtos, allSheet);
                excelWriter.write(targets, writeSheet);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 千万别忘记finish 会帮忙关闭流
                if (excelWriter != null) {
                    excelWriter.finish();
                }
            }
        }
    }

    /**
     * 生成dat
     *
     * @param newErtExcleDtos 所有
     * @param targets         目标
     * @param response        响应
     */
    private void createDat(List<ErtExcleDto> newErtExcleDtos, List<ErtTargetExcleDto> targets, String fileName, HttpServletResponse response) {
        System.out.println("生成dat");
        FileWriter newErtWriter = null;
        FileWriter targetsWriter = null;
        String serverpath = "/opt/geomative/jar/ertBuild/" + IdUtil.fastSimpleUUID() + "/";
        try {
            File newErtFile = new File(serverpath + "1-" + fileName + ".dat");
            FileUtil.touch(newErtFile);
            newErtWriter = new FileWriter(newErtFile);
            newErtWriter.write("point,north,east,elv\n");
            for (ErtExcleDto item : newErtExcleDtos) {
                newErtWriter.append(item.getPoint() + "," + item.getNorth() + "," + item.getEast() + "," + item.getElv() + "\n");
            }
            newErtWriter.flush();
            File targetsFile = new File(serverpath + "2-" + fileName + ".dat");
            FileUtil.touch(targetsFile);
            targetsWriter = new FileWriter(targetsFile);
            targetsWriter.write("point,elevation,resistivity,x,y,elv,eleDepth\n");
            for (ErtTargetExcleDto item : targets) {
                targetsWriter.append(item.getPoint() + "," + item.getElevation() + "," + item.getResistivity() + "," + item.getX()
                        + "," + item.getY() + "," + item.getElv() + "," + item.getEleDepth() + "\n");
            }
            targetsWriter.flush();
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".zip");
            ZipUtil.pack(new File(serverpath), response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (newErtWriter != null) {
                try {
                    newErtWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (targetsWriter != null) {
                try {
                    targetsWriter.close();
                    FileUtil.del(serverpath);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @PostMapping("mergeDat")
    public void mergeDat(@RequestParam("file") MultipartFile file, HttpServletResponse response) throws IOException {
        System.out.println("开始合并");
        if (ObjectUtils.isEmpty(file)) {
            System.out.println("文件不存在！");
            return;
        }
        if (!file.getOriginalFilename().endsWith("zip")) {
            System.out.println("压缩包不是zip！");
            return;
        }
        response.setHeader("Content-disposition", "attachment;filename=" + DateUtil.now() + "-merge.dat");

        OutputStream outputStream = response.getOutputStream();
        ZipUtil.iterate(file.getInputStream(), (in, zipEntry) -> {
            if (zipEntry.getName().endsWith(".dat")) {
                IoUtil.copy(in, outputStream, IoUtil.DEFAULT_BUFFER_SIZE);
            }
        });
    }

}
